/*
 * This is Melet, a salary slip designer. Feed it with data regarding to salary payment, prepare it for print through the graphical presentation, and you have it done.
 * Copyright (C) 2014, AFDiaX
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * This program is based on UMLet, a Free UML Tool for Fast UML Diagrams.
 * To contact the authors of UMLet visit https://code.google.com/p/umlet/people/list
 * To contact the authors of Melet visit https://gna.org/users/gabocze
 */
package com.baselet.gui;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JLayer;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.border.EtchedBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.LayerUI;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import javax.swing.text.BadLocationException;

import com.baselet.control.Main;
import com.baselet.control.basics.geom.Point;
import com.baselet.control.basics.geom.Rectangle;
import com.baselet.control.config.Config;
import com.baselet.control.constants.Constants;
import com.baselet.control.enums.ElementId;
import com.baselet.control.enums.Program;
import com.baselet.custom.CustomElementPanel;
import com.baselet.diagram.CurrentDiagram;
import com.baselet.diagram.DrawPanel;
import com.baselet.diagram.PaletteHandler;
import com.baselet.element.ElementFactorySwing;
import com.baselet.element.NewGridElement;
import com.baselet.element.interfaces.GridElement;
import com.baselet.element.old.custom.CustomElementHandler;
import com.baselet.gui.helper.DecoratedJComponentTwins;
import com.baselet.gui.listener.DividerListener;
import com.baselet.gui.listener.PaletteComboBoxListener;
import com.baselet.gui.listener.PropertyPanelListener;
import com.baselet.gui.listener.UpdateDrawPanelDocumentListener;
import com.baselet.gui.pane.OwnSyntaxPane;

public abstract class BaseGUIBuilder {

	private JPanel palettePanel;
	private CardLayout palettePanelLayout;
	private JSplitPane rightSplit;
	private JComboBox paletteList;

	private CustomElementHandler customHandler;
	private JSplitPane mainSplit;
	private MailPanel mailPanel;
	private JSplitPane customSplit;
	private JSplitPane mailSplit;
	private JPanel rightPanel;
	private OwnSyntaxPane propertyTextPane;
	private DecoratedJComponentTwins decoratedIterator;
	private UpdateDrawPanelDocumentListener mainListener;

	protected JSplitPane initBase(Component mainComponent, final int mainDividerLoc) {
		propertyTextPane = createPropertyTextPane(); // must be initialized before palettePanel because it could be accessed during palette initialization (eg in case of different default fontsize)
		palettePanel = newMyPalettePanel();
		//palettePanel.add(new JScrollPane(newMyPalettePanel(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS));
		//palettePanel.setPreferredSize(new Dimension(100,100));
		//palettePanel.setBackground(Color.red);
		//palettePanel.setBorder(BorderFactory.createLineBorder(Color.green, 6));
		JScrollPane scrollPane = new JScrollPane(palettePanel);
		scrollPane.setPreferredSize(new Dimension(200,50));  // http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html#sizing <-- Solucion� el problema de que el scrollpane se sal�a de las dimensiones de su contenedor (TODO Gabriel averiguar c�mo :)
		rightSplit = newGenericSplitPane(JSplitPane.VERTICAL_SPLIT, propertyTextPane.getPanel(), scrollPane, 2, 15, true);
		rightPanel = newRightPanel();

		mainSplit = newGenericSplitPane(JSplitPane.HORIZONTAL_SPLIT, rightPanel, mainComponent, 2, 500, true);
		mainListener.setComponent(mainSplit);
		// hide mainSplit on doubleclick
		((BasicSplitPaneUI) mainSplit.getUI()).getDivider().addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					rightPanel.setVisible(!rightPanel.isVisible());
					mainSplit.setDividerLocation(mainDividerLoc);
				}
			}
		});
		//JPanel myMainPanel = new JPanel(new BorderLayout());
		// El rightSplit tiene arriba el propertyPane y abajo el nuevo Scroll con mi nuevo panel/formulario
		// rightSplit contiene el formulario (nombre, fecha de ingreso, etc.) m�s un panel superior (rsyntax panel, un combobox para elegit paletas, etc.)
		// mainComponent contiene el TabbedPane, a su vez el JScrollPane y el DrawPane (el contenido gr�fico de la aplicaci�n)
		// mainSplit: la divisi�n entre ambos componentes, y tambi�n ambos componentes
		LayerUI<JComponent> layerUI = createMyRelationUI(palettePanel, mainComponent/*(Hay que conocer el lado derecho e izquierdo a trav�s de los cuales se va a dibujar)*/, decoratedIterator, mainSplit);
		JLayer<JComponent> layer = new JLayer<JComponent>(mainSplit, layerUI);  // creamos este layer para detectar eventos
		//myMainPanel.add(layer, BorderLayout.PAGE_START);
		//JLayeredPane layeredPane = new JLayeredPane();
		//layeredPane.setPreferredSize(new Dimension(1200,900));
		//layeredPane.setLayout(new GridLayout(1,1));
		//JButton button = new JButton("Press me");
		//layeredPane.add(button);
		//button.setBounds(0, -50, 200, 100);
//		layeredPane.add(layer);
//		layer.setBounds(0,0,1200, 650);
		//myMainPanel.add(layeredPane, BorderLayout.CENTER);
		
//		JPanel panel = new JPanel();
//		panel.add(layeredPane);
		customHandler = new CustomElementHandler();
		customHandler.getPanel().setVisible(false);
		customSplit = newGenericSplitPane(JSplitPane.VERTICAL_SPLIT, layer, getCustomPanel(), 0, 0, true);
		mailPanel = new MailPanel();
		mailPanel.setVisible(false);
		mailSplit = newGenericSplitPane(JSplitPane.VERTICAL_SPLIT, mailPanel, customSplit, 0, 0, true);
		
		return mailSplit;
	}

	public JSplitPane getMailSplit() {
		return mailSplit;
	}

	public JSplitPane getCustomSplit() {
		return customSplit;
	}

	public MailPanel getMailPanel() {
		return mailPanel;
	}

	public JSplitPane getMainSplit() {
		return mainSplit;
	}

	public JPanel getPalettePanel() {
		return palettePanel;
	}

	public JComboBox getPaletteList() {
		return paletteList;
	}

	public JSplitPane getRightSplit() {
		return rightSplit;
	}

	public CustomElementHandler getCustomHandler() {
		return customHandler;
	}

	public CustomElementPanel getCustomPanel() {
		return customHandler.getPanel();
	}

	public JPanel newPalettePanel() {
		palettePanelLayout = new CardLayout();
		JPanel palettePanel = new JPanel(palettePanelLayout);
		palettePanel.addComponentListener(new DividerListener()); // Adding the DividerListener which refreshes Scrollbars here is enough for all dividers
		for (PaletteHandler palette : Main.getInstance().getPalettes().values()) {
			palettePanel.add(palette.getDrawPanel().getScrollPane(), palette.getName());
		}
		return palettePanel;
	}

	/**
	 * 
	 */
	public JPanel newMyPalettePanel() {
		/* TODO Gabriel aplicar comportamiento a todos los JComponent's del form
		 * Iterador[Punto(coordenada inicial), Punto(coordenada final)] coordenada inicial=f(x=Children de c), coordenada final=f'(JComponent child de DrawPanel conectado a de x)
		 * 
		 * 
		 * Creaci�n - eliminaci�n de elementos en el diagrama(Evento change, Elemento de tipo Texto)
		 *    |->  (HECHO) Creaci�n de elementos : posici�n(x,y) en el diagrama(Array de puntos (x,y) precargado)
		 *    |->  (HECHO) Eliminaci�n de elementos : guardar (x,y) para volver a posicionarlo ante una nueva creaci�n(actualizar Array de Puntos(x,y)).
		 *    |->  (+) Creaci�n de elementos y modificaci�n del valor :  Tener asociado cada :GridElement en :DrawPanel al :JComponent asociado en newPalettePanel
		 *          |-> (HECHO) Edici�n del formulario (newPalettePanel) : Cambi� valor del :JComponent -> actualizar "Texto" del :GridElement
		 *          |-> Dibujo conector (MyRelationUI) : Iterador[x=child de returnPanel, :JComponent child de :DrawPanel conectado a x]
		 *    |->  (HECHO) Eliminaci�n de elementos: Dispara la acci�n :JComponent en newPalettePanel qued�="" -> borrar asociaci�n con GridElement
		 *    |->  (HECHO) Creaci�n de elementos : siempre en la capa superior (propiedad layer de los Element(baselet))
		 */
		JPanel returnPanel = new JPanel(new GridBagLayout());
	
		GridBagConstraints c = new GridBagConstraints();
		int gridy=0;
	
		c.anchor = GridBagConstraints.LINE_START;
		c.gridy=gridy++;
		returnPanel.add(new JLabel("Nombre"), c);
		c.gridx = 1;
		c.weightx = 0.7;
		c.fill = GridBagConstraints.HORIZONTAL;
		JTextField nombreTextField = new JTextField();
		returnPanel.add(nombreTextField, c);
		
		c.gridx = 2;
		c.weightx = 0;
		c.fill = GridBagConstraints.NONE;
		returnPanel.add(new JButton("Cargar Datos..."), c);
		//((JButton)returnPanel.getComponent(returnPanel.getComponentCount()-1)).setMargin(new Insets(200,0,400,0));
		c.gridx = 3;
		c.weightx = 0.3;
		c.fill = GridBagConstraints.NONE;
		returnPanel.add(new JLabel(""), c);   // path del archivo cargado
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("Fecha de ingreso"),c);
		c.gridx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridwidth = GridBagConstraints.REMAINDER;
		JTextField fechaIngresoTextField = new JTextField();
		returnPanel.add(fechaIngresoTextField, c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("Fecha de finalizaci�n (fijo)"),c);
		c.gridx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridwidth = GridBagConstraints.REMAINDER;
		JTextField fechaFinalizacionTextField = new JTextField();
		returnPanel.add(fechaFinalizacionTextField, c);
		c.gridy = gridy++;
		c.gridx = 0;
		returnPanel.add(new JLabel("Remuneraci�n bruta asignada"), c);
		c.gridx = 1;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridwidth = GridBagConstraints.REMAINDER;
		JTextField remuneracionBrutaTextField = new JTextField();
		returnPanel.add(remuneracionBrutaTextField, c);
		c.gridy=gridy++;
		c.gridx=0;
		JPanel premiosPanel = new JPanel();
		premiosPanel.add(new JCheckBox("Eficiencia"));
		premiosPanel.add(new JCheckBox("Asistencia"));
		premiosPanel.add(new JCheckBox("Producci�n"));
		premiosPanel.add(new JCheckBox("Especiales"));
		premiosPanel.add(new JCheckBox("Doble Aguinaldo"));
		premiosPanel.setBorder(BorderFactory.createTitledBorder("Premios"));
		returnPanel.add(premiosPanel,c);
		c.gridy = gridy++;
		c.gridx = 0;
		returnPanel.add(new JLabel("Tipo de jornada"), c);
		c.gridx = 1;
		returnPanel.add(new JComboBox<String>(new String[]{"7 hs. diarias", "8 hs. diarias", "9 hs. diarias", "45 hs. semanales", "176 hs. mensuales", "200 hs. mensuales"}), c);
		c.gridy=gridy++;
		c.gridx=0;
		JPanel horasExtraPanel = new JPanel(new GridLayout(0,2));
		horasExtraPanel.add(new JLabel("Al 50%"));
		horasExtraPanel.add(new JTextField());
		horasExtraPanel.add(new JLabel("Al 100%"));
		horasExtraPanel.add(new JTextField());
		horasExtraPanel.add(new JLabel("Guardias"));
		horasExtraPanel.add(new JTextField());
		horasExtraPanel.add(new JLabel("Domicilios"));
		horasExtraPanel.add(new JTextField());
		horasExtraPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Horas extra trabajadas"),BorderFactory.createEmptyBorder(0, 50, 0, 50)));
		returnPanel.add(horasExtraPanel,c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("Feriados trabajados"),c);
		c.gridx = 1;
		returnPanel.add(new JTextField(), c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JCheckBox("D�a de conmemoraci�n al gremio"),c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("Vacaciones"),c);
		c.gridx = 1;
		returnPanel.add(new JTextField(), c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JCheckBox("Aguinaldo"),c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("Vacaciones no gozadas"),c);
		c.gridx = 1;
		returnPanel.add(new JTextField(), c);
		c.gridy = gridy++;
		c.gridx = 0;
		returnPanel.add(new JLabel("Tipo de aporte"), c);
		c.gridx = 1;
		returnPanel.add(new JComboBox<String>(new String[]{"SMATA", "UOM", "ASIMRA", "SEC", "UTA"}), c);
		c.gridy = gridy++;
		c.gridx = 0;
		returnPanel.add(new JLabel("Obra social"), c);
		c.gridx = 1;
		returnPanel.add(new JComboBox<String>(new String[]{"OSPACA", "OSPOCE", "OSPIQYP", "OSECAC", "OSUOMRA"}), c);
		c.gridy = gridy++;
		c.gridx = 0;
		returnPanel.add(new JLabel("Medicina prepaga"), c);
		c.gridx = 1;
		returnPanel.add(new JComboBox<String>(new String[]{"GALENO", "OSDE", "Swiss Medical"}), c);
		c.gridy=gridy++;
		c.gridx=0;
		JPanel licenciasPanel = new JPanel(new GridLayout(0,2));
		licenciasPanel.add(new JLabel("Enfermedad"));
		licenciasPanel.add(new JTextField());
		licenciasPanel.add(new JLabel("Estudio"));
		licenciasPanel.add(new JTextField());
		licenciasPanel.add(new JLabel("Fallecimiento familiar"));
		licenciasPanel.add(new JTextField());
		licenciasPanel.add(new JLabel("Nacimiento"));
		licenciasPanel.add(new JTextField());
		licenciasPanel.add(new JLabel("Embarazo"));
		licenciasPanel.add(new JTextField());
		licenciasPanel.add(new JLabel("Casamiento"));
		licenciasPanel.add(new JTextField());
		licenciasPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Licencias personales"),BorderFactory.createEmptyBorder(0, 50, 0, 50)));
		returnPanel.add(licenciasPanel,c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("Retenci�n de ganacias"),c);
		c.gridx = 1;
		returnPanel.add(new JTextField(), c);
		c.gridy = gridy++;
		c.gridx = 0;
		returnPanel.add(new JLabel("M�todo de pago"), c);
		c.gridx = 1;
		returnPanel.add(new JComboBox<String>(new String[]{"Efectivo", "Transferencia bancaria", "Cheque"}), c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JCheckBox("Convenio banco"),c);
		c.gridy=gridy++;
		c.gridx=0;
		returnPanel.add(new JLabel("NETO ##.###,##"),c);
		((JLabel)returnPanel.getComponent(returnPanel.getComponentCount()-1)).setFont(returnPanel.getFont().deriveFont(16.f));	
		
		//returnPanel.setBorder(BorderFactory.createEmptyBorder(10, 100, 10, 100));
		
		Map<Object, Point> defaultLocations = new HashMap<Object, Point>();
		defaultLocations.put(nombreTextField, new Point(100,40));
		defaultLocations.put(fechaIngresoTextField, new Point(100, 200));
		defaultLocations.put(fechaFinalizacionTextField, new Point(100, 300));
		defaultLocations.put(remuneracionBrutaTextField, new Point(100, 400));
		Map<JComponent, GridElement>associations=new HashMap<JComponent, GridElement>();
		UpdateDrawPanelDocumentListener listener = new UpdateDrawPanelDocumentListener(defaultLocations, associations);
		
		nombreTextField.getDocument().addDocumentListener(listener);
		((Component)nombreTextField).setName("nombreTextField");
		nombreTextField.getDocument().putProperty("source", nombreTextField);
		fechaIngresoTextField.getDocument().addDocumentListener(listener);
		fechaIngresoTextField.getDocument().putProperty("source", fechaIngresoTextField);
		fechaFinalizacionTextField.getDocument().addDocumentListener(listener);
		fechaFinalizacionTextField.getDocument().putProperty("source", fechaFinalizacionTextField);
		remuneracionBrutaTextField.getDocument().addDocumentListener(listener);
		remuneracionBrutaTextField.getDocument().putProperty("source", remuneracionBrutaTextField);
		
		mainListener = listener;
		decoratedIterator = new DecoratedJComponentTwins(associations.entrySet());
		
		return returnPanel;
	}

	public JSplitPane newGenericSplitPane(int newOrientation, Component newLeftComponent, Component newRightComponent, int dividerSize, int dividerLocation, boolean visible) {
		JSplitPane pane = new JSplitPane(newOrientation, newLeftComponent, newRightComponent);
		pane.setDividerSize(dividerSize);
		pane.setDividerLocation(dividerLocation);
		pane.setResizeWeight(1);
		pane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0), 0));
		pane.setAlignmentX(Component.RIGHT_ALIGNMENT);
		pane.setVisible(visible);
		return pane;
	}

	private JPanel newRightPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		rightSplit.setAlignmentX(Component.CENTER_ALIGNMENT);
		panel.add(newPaletteControlsPanel());
		panel.add(rightSplit);
		return panel;
	}

	private JPanel newPaletteControlsPanel() {
		createPaletteList();

		JPanel paletteControlsPanel = new JPanel();
		paletteControlsPanel.setLayout(new BoxLayout(paletteControlsPanel, BoxLayout.X_AXIS));
		paletteControlsPanel.add(paletteList);
		return paletteControlsPanel;
	}

	public void createPaletteList() {
		paletteList = new JComboBox();
		paletteList.setMaximumRowCount(15);
		paletteList.setAlignmentX(Component.CENTER_ALIGNMENT);
		for (PaletteHandler palette : Main.getInstance().getPalettes().values()) {
			paletteList.addItem(palette.getName());
		}
		PaletteComboBoxListener pl = new PaletteComboBoxListener();
		paletteList.addActionListener(pl); // add listeners after adding every paletteList entry to avoid triggering the listener everytime
		paletteList.addMouseWheelListener(pl);

		// only set last used palette if the program version has not changed and if lastUsedPalette is not null (if the version is not equal or the lastUsedPalette String is invalid it will simply stay at index 0; null must not be set because it invalidates the selectionstate instead of setting it to 0; see Issue 215)
		String lastUsedPalette = Config.getInstance().getLastUsedPalette();
		if (Program.getInstance().getVersion().equals(Config.getInstance().getProgramVersion()) && lastUsedPalette != null) {
			paletteList.setSelectedItem(lastUsedPalette);
		}
	}

	private OwnSyntaxPane createPropertyTextPane() {
		OwnSyntaxPane propertyTextPane = new OwnSyntaxPane();
		PropertyPanelListener pListener = new PropertyPanelListener();
		propertyTextPane.getTextComponent().addKeyListener(pListener);
		propertyTextPane.getTextComponent().getDocument().addDocumentListener(pListener);
		return propertyTextPane;
	}

	public OwnSyntaxPane getPropertyTextPane() {
		return propertyTextPane;
	}

	public void setMailPanelEnabled(boolean enable) {
		getMailPanel().setVisible(enable);
		if (enable) {
			int mailDividerLoc = Math.max(Constants.MIN_MAIL_SPLITPANEL_SIZE, Config.getInstance().getMail_split_position());
			mailSplit.setDividerLocation(mailDividerLoc);
			mailSplit.setDividerSize(2);
		}
		else {
			mailSplit.setDividerSize(0);
		}
	}

	public void setCustomPanelEnabled(boolean enable) {
		CustomElementPanel customPanel = getCustomPanel();
		if (customPanel.isVisible() != enable) {
			int loc = getMainSplit().getDividerLocation();
			customPanel.setVisible(enable);

			if (enable) {
				int rightloc = getRightSplit().getDividerLocation();

				getCustomSplit().setDividerSize(2);
				getRightSplit().setDividerSize(0);

				customPanel.getLeftSplit().setLeftComponent(propertyTextPane.getPanel());
				getCustomSplit().setDividerLocation(rightloc);

				customPanel.getRightSplit().setDividerLocation(loc);
				customPanel.getLeftSplit().setDividerLocation(CurrentDiagram.getInstance().getDiagramHandler().getDrawPanel().getWidth() / 2);
				customPanel.getLeftSplit().updateUI();
			}
			else {
				int rightloc = getCustomSplit().getDividerLocation();
				getCustomSplit().setDividerSize(0);

				getRightSplit().setDividerSize(2);
				getRightSplit().setRightComponent(propertyTextPane.getPanel());
				getRightSplit().setDividerLocation(rightloc);
			}
			getMainSplit().setDividerLocation(loc);
		}
	}

	public void setPaletteActive(String paletteName) {
		//palettePanelLayout.show(palettePanel, paletteName);
	}

	public LayerUI<JComponent> createMyRelationUI(JComponent leftTarget, Component rightTarget, DecoratedJComponentTwins drawIterator, JComponent decoratedTarget) {
		MyRelationUI layerUI = new MyRelationUI();
		layerUI.leftTarget = leftTarget;
		layerUI.rightTarget = rightTarget;
		layerUI.drawIterator = drawIterator;
		layerUI.decoratedTarget = decoratedTarget;  // Better knowing all the surface than each subsection apiece (leftTarget and rightTarget).
		return layerUI;
	}
}
